<!DOCTYPE html>
<html>
<head>
  <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
  <title>The source code</title>
  <link href="../resources/prettify/prettify.css" type="text/css" rel="stylesheet" />
  <script type="text/javascript" src="../resources/prettify/prettify.js"></script>
  <style type="text/css">
    .highlight { display: block; background-color: #ddd; }
  </style>
  <script type="text/javascript">
    function highlight() {
      document.getElementById(location.hash.replace(/#/, "")).className = "highlight";
    }
  </script>
</head>
<body onload="prettyPrint(); highlight();">
  <pre class="prettyprint lang-js"><span id='Ext-layout-boxOverflow-Scroller'>/**
</span> * @class Ext.layout.boxOverflow.Scroller
 * @extends Ext.layout.boxOverflow.None
 * Description
 */
Ext.layout.boxOverflow.Scroller = Ext.extend(Ext.layout.boxOverflow.None, {
<span id='Ext-layout-boxOverflow-Scroller-property-animateScroll'>    /**
</span>     * @cfg animateScroll
     * @type Boolean
     * True to animate the scrolling of items within the layout (defaults to true, ignored if enableScroll is false)
     */
    animateScroll: true,
    
<span id='Ext-layout-boxOverflow-Scroller-property-scrollIncrement'>    /**
</span>     * @cfg scrollIncrement
     * @type Number
     * The number of pixels to scroll by on scroller click (defaults to 100)
     */
    scrollIncrement: 100,
    
<span id='Ext-layout-boxOverflow-Scroller-property-wheelIncrement'>    /**
</span>     * @cfg wheelIncrement
     * @type Number
     * The number of pixels to increment on mouse wheel scrolling (defaults to &lt;tt&gt;3&lt;/tt&gt;).
     */
    wheelIncrement: 3,
    
<span id='Ext-layout-boxOverflow-Scroller-property-scrollRepeatInterval'>    /**
</span>     * @cfg scrollRepeatInterval
     * @type Number
     * Number of milliseconds between each scroll while a scroller button is held down (defaults to 400)
     */
    scrollRepeatInterval: 400,
    
<span id='Ext-layout-boxOverflow-Scroller-property-scrollDuration'>    /**
</span>     * @cfg scrollDuration
     * @type Number
     * Number of seconds that each scroll animation lasts (defaults to 0.4)
     */
    scrollDuration: 0.4,
    
<span id='Ext-layout-boxOverflow-Scroller-property-beforeCls'>    /**
</span>     * @cfg beforeCls
     * @type String
     * CSS class added to the beforeCt element. This is the element that holds any special items such as scrollers,
     * which must always be present at the leftmost edge of the Container
     */
    beforeCls: 'x-strip-left',
    
<span id='Ext-layout-boxOverflow-Scroller-property-afterCls'>    /**
</span>     * @cfg afterCls
     * @type String
     * CSS class added to the afterCt element. This is the element that holds any special items such as scrollers,
     * which must always be present at the rightmost edge of the Container
     */
    afterCls: 'x-strip-right',
    
<span id='Ext-layout-boxOverflow-Scroller-property-scrollerCls'>    /**
</span>     * @cfg scrollerCls
     * @type String
     * CSS class added to both scroller elements if enableScroll is used
     */
    scrollerCls: 'x-strip-scroller',
    
<span id='Ext-layout-boxOverflow-Scroller-property-beforeScrollerCls'>    /**
</span>     * @cfg beforeScrollerCls
     * @type String
     * CSS class added to the left scroller element if enableScroll is used
     */
    beforeScrollerCls: 'x-strip-scroller-left',
    
<span id='Ext-layout-boxOverflow-Scroller-property-afterScrollerCls'>    /**
</span>     * @cfg afterScrollerCls
     * @type String
     * CSS class added to the right scroller element if enableScroll is used
     */
    afterScrollerCls: 'x-strip-scroller-right',
    
<span id='Ext-layout-boxOverflow-Scroller-method-createWheelListener'>    /**
</span>     * @private
     * Sets up an listener to scroll on the layout's innerCt mousewheel event
     */
    createWheelListener: function() {
        this.layout.innerCt.on({
            scope     : this,
            mousewheel: function(e) {
                e.stopEvent();

                this.scrollBy(e.getWheelDelta() * this.wheelIncrement * -1, false);
            }
        });
    },
    
<span id='Ext-layout-boxOverflow-Scroller-method-handleOverflow'>    /**
</span>     * @private
     * Most of the heavy lifting is done in the subclasses
     */
    handleOverflow: function(calculations, targetSize) {
        this.createInnerElements();
        this.showScrollers();
    },
    
<span id='Ext-layout-boxOverflow-Scroller-method-clearOverflow'>    /**
</span>     * @private
     */
    clearOverflow: function() {
        this.hideScrollers();
    },
    
<span id='Ext-layout-boxOverflow-Scroller-method-showScrollers'>    /**
</span>     * @private
     * Shows the scroller elements in the beforeCt and afterCt. Creates the scrollers first if they are not already
     * present. 
     */
    showScrollers: function() {
        this.createScrollers();
        
        this.beforeScroller.show();
        this.afterScroller.show();
        
        this.updateScrollButtons();
    },
    
<span id='Ext-layout-boxOverflow-Scroller-method-hideScrollers'>    /**
</span>     * @private
     * Hides the scroller elements in the beforeCt and afterCt
     */
    hideScrollers: function() {
        if (this.beforeScroller != undefined) {
            this.beforeScroller.hide();
            this.afterScroller.hide();          
        }
    },
    
<span id='Ext-layout-boxOverflow-Scroller-method-createScrollers'>    /**
</span>     * @private
     * Creates the clickable scroller elements and places them into the beforeCt and afterCt
     */
    createScrollers: function() {
        if (!this.beforeScroller &amp;&amp; !this.afterScroller) {
            var before = this.beforeCt.createChild({
                cls: String.format(&quot;{0} {1} &quot;, this.scrollerCls, this.beforeScrollerCls)
            });
            
            var after = this.afterCt.createChild({
                cls: String.format(&quot;{0} {1}&quot;, this.scrollerCls, this.afterScrollerCls)
            });
            
            before.addClassOnOver(this.beforeScrollerCls + '-hover');
            after.addClassOnOver(this.afterScrollerCls + '-hover');
            
            before.setVisibilityMode(Ext.Element.DISPLAY);
            after.setVisibilityMode(Ext.Element.DISPLAY);
            
            this.beforeRepeater = new Ext.util.ClickRepeater(before, {
                interval: this.scrollRepeatInterval,
                handler : this.scrollLeft,
                scope   : this
            });
            
            this.afterRepeater = new Ext.util.ClickRepeater(after, {
                interval: this.scrollRepeatInterval,
                handler : this.scrollRight,
                scope   : this
            });
            
<span id='Ext-layout-boxOverflow-Scroller-property-beforeScroller'>            /**
</span>             * @property beforeScroller
             * @type Ext.Element
             * The left scroller element. Only created when needed.
             */
            this.beforeScroller = before;
            
<span id='Ext-layout-boxOverflow-Scroller-property-afterScroller'>            /**
</span>             * @property afterScroller
             * @type Ext.Element
             * The left scroller element. Only created when needed.
             */
            this.afterScroller = after;
        }
    },
    
<span id='Ext-layout-boxOverflow-Scroller-method-destroy'>    /**
</span>     * @private
     */
    destroy: function() {
        Ext.destroy(this.beforeScroller, this.afterScroller, this.beforeRepeater, this.afterRepeater, this.beforeCt, this.afterCt);
    },
    
<span id='Ext-layout-boxOverflow-Scroller-method-scrollBy'>    /**
</span>     * @private
     * Scrolls left or right by the number of pixels specified
     * @param {Number} delta Number of pixels to scroll to the right by. Use a negative number to scroll left
     */
    scrollBy: function(delta, animate) {
        this.scrollTo(this.getScrollPosition() + delta, animate);
    },
    
<span id='Ext-layout-boxOverflow-Scroller-method-getItem'>    /**
</span>     * @private
     * Normalizes an item reference, string id or numerical index into a reference to the item
     * @param {Ext.Component|String|Number} item The item reference, id or index
     * @return {Ext.Component} The item
     */
    getItem: function(item) {
        if (Ext.isString(item)) {
            item = Ext.getCmp(item);
        } else if (Ext.isNumber(item)) {
            item = this.items[item];
        }
        
        return item;
    },
    
<span id='Ext-layout-boxOverflow-Scroller-method-getScrollAnim'>    /**
</span>     * @private
     * @return {Object} Object passed to scrollTo when scrolling
     */
    getScrollAnim: function() {
        return {
            duration: this.scrollDuration, 
            callback: this.updateScrollButtons, 
            scope   : this
        };
    },
    
<span id='Ext-layout-boxOverflow-Scroller-method-updateScrollButtons'>    /**
</span>     * @private
     * Enables or disables each scroller button based on the current scroll position
     */
    updateScrollButtons: function() {
        if (this.beforeScroller == undefined || this.afterScroller == undefined) {
            return;
        }
        
        var beforeMeth = this.atExtremeBefore()  ? 'addClass' : 'removeClass',
            afterMeth  = this.atExtremeAfter() ? 'addClass' : 'removeClass',
            beforeCls  = this.beforeScrollerCls + '-disabled',
            afterCls   = this.afterScrollerCls  + '-disabled';
        
        this.beforeScroller[beforeMeth](beforeCls);
        this.afterScroller[afterMeth](afterCls);
        this.scrolling = false;
    },
    
<span id='Ext-layout-boxOverflow-Scroller-method-atExtremeBefore'>    /**
</span>     * @private
     * Returns true if the innerCt scroll is already at its left-most point
     * @return {Boolean} True if already at furthest left point
     */
    atExtremeBefore: function() {
        return this.getScrollPosition() === 0;
    },
    
<span id='Ext-layout-boxOverflow-Scroller-method-scrollLeft'>    /**
</span>     * @private
     * Scrolls to the left by the configured amount
     */
    scrollLeft: function(animate) {
        this.scrollBy(-this.scrollIncrement, animate);
    },
    
<span id='Ext-layout-boxOverflow-Scroller-method-scrollRight'>    /**
</span>     * @private
     * Scrolls to the right by the configured amount
     */
    scrollRight: function(animate) {
        this.scrollBy(this.scrollIncrement, animate);
    },
    
<span id='Ext-layout-boxOverflow-Scroller-method-scrollToItem'>    /**
</span>     * Scrolls to the given component.
     * @param {String|Number|Ext.Component} item The item to scroll to. Can be a numerical index, component id 
     * or a reference to the component itself.
     * @param {Boolean} animate True to animate the scrolling
     */
    scrollToItem: function(item, animate) {
        item = this.getItem(item);
        
        if (item != undefined) {
            var visibility = this.getItemVisibility(item);
            
            if (!visibility.fullyVisible) {
                var box  = item.getBox(true, true),
                    newX = box.x;
                    
                if (visibility.hiddenRight) {
                    newX -= (this.layout.innerCt.getWidth() - box.width);
                }
                
                this.scrollTo(newX, animate);
            }
        }
    },
    
<span id='Ext-layout-boxOverflow-Scroller-method-getItemVisibility'>    /**
</span>     * @private
     * For a given item in the container, return an object with information on whether the item is visible
     * with the current innerCt scroll value.
     * @param {Ext.Component} item The item
     * @return {Object} Values for fullyVisible, hiddenLeft and hiddenRight
     */
    getItemVisibility: function(item) {
        var box         = this.getItem(item).getBox(true, true),
            itemLeft    = box.x,
            itemRight   = box.x + box.width,
            scrollLeft  = this.getScrollPosition(),
            scrollRight = this.layout.innerCt.getWidth() + scrollLeft;
        
        return {
            hiddenLeft  : itemLeft &lt; scrollLeft,
            hiddenRight : itemRight &gt; scrollRight,
            fullyVisible: itemLeft &gt; scrollLeft &amp;&amp; itemRight &lt; scrollRight
        };
    }
});

Ext.layout.boxOverflow.scroller = Ext.layout.boxOverflow.Scroller;


<span id='Ext-layout-boxOverflow-VerticalScroller'>/**
</span> * @class Ext.layout.boxOverflow.VerticalScroller
 * @extends Ext.layout.boxOverflow.Scroller
 * Description
 */
Ext.layout.boxOverflow.VerticalScroller = Ext.extend(Ext.layout.boxOverflow.Scroller, {
<span id='Ext-layout-boxOverflow-VerticalScroller-property-scrollIncrement'>    scrollIncrement: 75,
</span><span id='Ext-layout-boxOverflow-VerticalScroller-property-wheelIncrement'>    wheelIncrement : 2,
</span>    
<span id='Ext-layout-boxOverflow-VerticalScroller-method-handleOverflow'>    handleOverflow: function(calculations, targetSize) {
</span>        Ext.layout.boxOverflow.VerticalScroller.superclass.handleOverflow.apply(this, arguments);
        
        return {
            targetSize: {
                height: targetSize.height - (this.beforeCt.getHeight() + this.afterCt.getHeight()),
                width : targetSize.width
            }
        };
    },
    
<span id='Ext-layout-boxOverflow-VerticalScroller-method-createInnerElements'>    /**
</span>     * @private
     * Creates the beforeCt and afterCt elements if they have not already been created
     */
    createInnerElements: function() {
        var target = this.layout.innerCt;
        
        //normal items will be rendered to the innerCt. beforeCt and afterCt allow for fixed positioning of
        //special items such as scrollers or dropdown menu triggers
        if (!this.beforeCt) {
            this.beforeCt = target.insertSibling({cls: this.beforeCls}, 'before');
            this.afterCt  = target.insertSibling({cls: this.afterCls},  'after');

            this.createWheelListener();
        }
    },
    
<span id='Ext-layout-boxOverflow-VerticalScroller-method-scrollTo'>    /**
</span>     * @private
     * Scrolls to the given position. Performs bounds checking.
     * @param {Number} position The position to scroll to. This is constrained.
     * @param {Boolean} animate True to animate. If undefined, falls back to value of this.animateScroll
     */
    scrollTo: function(position, animate) {
        var oldPosition = this.getScrollPosition(),
            newPosition = position.constrain(0, this.getMaxScrollBottom());
        
        if (newPosition != oldPosition &amp;&amp; !this.scrolling) {
            if (animate == undefined) {
                animate = this.animateScroll;
            }
            
            this.layout.innerCt.scrollTo('top', newPosition, animate ? this.getScrollAnim() : false);
            
            if (animate) {
                this.scrolling = true;
            } else {
                this.scrolling = false;
                this.updateScrollButtons();
            }
        }
    },
    
<span id='Ext-layout-boxOverflow-VerticalScroller-method-getScrollPosition'>    /**
</span>     * Returns the current scroll position of the innerCt element
     * @return {Number} The current scroll position
     */
    getScrollPosition: function(){
        return parseInt(this.layout.innerCt.dom.scrollTop, 10) || 0;
    },
    
<span id='Ext-layout-boxOverflow-VerticalScroller-method-getMaxScrollBottom'>    /**
</span>     * @private
     * Returns the maximum value we can scrollTo
     * @return {Number} The max scroll value
     */
    getMaxScrollBottom: function() {
        return this.layout.innerCt.dom.scrollHeight - this.layout.innerCt.getHeight();
    },
    
<span id='Ext-layout-boxOverflow-VerticalScroller-method-atExtremeAfter'>    /**
</span>     * @private
     * Returns true if the innerCt scroll is already at its right-most point
     * @return {Boolean} True if already at furthest right point
     */
    atExtremeAfter: function() {
        return this.getScrollPosition() &gt;= this.getMaxScrollBottom();
    }
});

Ext.layout.boxOverflow.scroller.vbox = Ext.layout.boxOverflow.VerticalScroller;


<span id='Ext-layout-boxOverflow-HorizontalScroller'>/**
</span> * @class Ext.layout.boxOverflow.HorizontalScroller
 * @extends Ext.layout.boxOverflow.Scroller
 * Description
 */
Ext.layout.boxOverflow.HorizontalScroller = Ext.extend(Ext.layout.boxOverflow.Scroller, {
<span id='Ext-layout-boxOverflow-HorizontalScroller-method-handleOverflow'>    handleOverflow: function(calculations, targetSize) {
</span>        Ext.layout.boxOverflow.HorizontalScroller.superclass.handleOverflow.apply(this, arguments);
        
        return {
            targetSize: {
                height: targetSize.height,
                width : targetSize.width - (this.beforeCt.getWidth() + this.afterCt.getWidth())
            }
        };
    },
    
<span id='Ext-layout-boxOverflow-HorizontalScroller-method-createInnerElements'>    /**
</span>     * @private
     * Creates the beforeCt and afterCt elements if they have not already been created
     */
    createInnerElements: function() {
        var target = this.layout.innerCt;
        
        //normal items will be rendered to the innerCt. beforeCt and afterCt allow for fixed positioning of
        //special items such as scrollers or dropdown menu triggers
        if (!this.beforeCt) {
            this.afterCt  = target.insertSibling({cls: this.afterCls},  'before');
            this.beforeCt = target.insertSibling({cls: this.beforeCls}, 'before');
            
            this.createWheelListener();
        }
    },
    
<span id='Ext-layout-boxOverflow-HorizontalScroller-method-scrollTo'>    /**
</span>     * @private
     * Scrolls to the given position. Performs bounds checking.
     * @param {Number} position The position to scroll to. This is constrained.
     * @param {Boolean} animate True to animate. If undefined, falls back to value of this.animateScroll
     */
    scrollTo: function(position, animate) {
        var oldPosition = this.getScrollPosition(),
            newPosition = position.constrain(0, this.getMaxScrollRight());
        
        if (newPosition != oldPosition &amp;&amp; !this.scrolling) {
            if (animate == undefined) {
                animate = this.animateScroll;
            }
            
            this.layout.innerCt.scrollTo('left', newPosition, animate ? this.getScrollAnim() : false);
            
            if (animate) {
                this.scrolling = true;
            } else {
                this.scrolling = false;
                this.updateScrollButtons();
            }
        }
    },
    
<span id='Ext-layout-boxOverflow-HorizontalScroller-method-getScrollPosition'>    /**
</span>     * Returns the current scroll position of the innerCt element
     * @return {Number} The current scroll position
     */
    getScrollPosition: function(){
        return parseInt(this.layout.innerCt.dom.scrollLeft, 10) || 0;
    },
    
<span id='Ext-layout-boxOverflow-HorizontalScroller-method-getMaxScrollRight'>    /**
</span>     * @private
     * Returns the maximum value we can scrollTo
     * @return {Number} The max scroll value
     */
    getMaxScrollRight: function() {
        return this.layout.innerCt.dom.scrollWidth - this.layout.innerCt.getWidth();
    },
    
<span id='Ext-layout-boxOverflow-HorizontalScroller-method-atExtremeAfter'>    /**
</span>     * @private
     * Returns true if the innerCt scroll is already at its right-most point
     * @return {Boolean} True if already at furthest right point
     */
    atExtremeAfter: function() {
        return this.getScrollPosition() &gt;= this.getMaxScrollRight();
    }
});

Ext.layout.boxOverflow.scroller.hbox = Ext.layout.boxOverflow.HorizontalScroller;</pre>
</body>
</html>
